package com.bsoft.gol.hbs.service.impl.sysroute;

import com.bsoft.gol.hbs.dao.*;
import com.bsoft.gol.hbs.service.impl.sysroute.dto.*;
import com.bsoft.gol.hbs.service.impl.sysroute.vo.ServiceConfigDetailVO;
import com.bsoft.gol.hbs.service.impl.sysroute.vo.ServiceConfigListVO;
import com.bsoft.gol.hbs.service.impl.sysroute.vo.SystemConfigListVO;
import com.bsoft.gol.hbs.service.impl.sysroute.vo.SystemConfigVO;
import com.bsoft.gol.hbs.utils.HcnBaseConst;
import ctd.account.UserRoleToken;
import ctd.account.user.User;
import ctd.account.user.controller.UserController;
import ctd.controller.exception.ControllerException;
import ctd.dictionary.Dictionary;
import ctd.dictionary.DictionaryItem;
import ctd.dictionary.controller.DictionaryController;
import ctd.persistence.annotation.DAOTransaction;
import ctd.spring.boot.annotation.SsdevService;
import ctd.util.JSONUtils;
import ctd.util.KeyGenerator;
import ctd.util.annotation.RpcService;
import hcn.base.*;
import hcn.enums.PlatFormServiceEnum;
import hcn.enums.SystemTypeEnum;
import hcn.service.base.IServConfService;
import hcn.service.base.qo.ServiceConfigQo;
import hcn.service.base.vo.ServiceConfigVO;
import lombok.extern.slf4j.Slf4j;
import org.atag.core.exception.ServiceException;
import org.atag.dao.model.SimplePageInfo;
import org.atag.sysrouter.model.base.TemplateDTO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 外部系统服务配置服务层
 *
 * @author neoLin - 2022/09/21 14:14
 **/
@Slf4j
@SsdevService("servConfService")
public class ServConfServiceImpl implements IServConfService {


    @Autowired
    private ServBaseConfDAO servBaseConfDAO;

    @Autowired
    private ServItemConfDAO servItemConfDAO;

    @Autowired
    private ServItemTemplateDAO servItemTemplateDAO;

    @Autowired
    private ServDictMappingDAO servItemMappingDAO;

    @Autowired
    private ServAuthConfigDAO servAuthConfigDAO;


    @Override
    public ServiceConfigVO queryServiceConfig(ServiceConfigQo qo) {
        String tenantId = qo.getTenantId();
        String serviceName = qo.getServiceName();
        String orgCode = qo.getOrgCode();
        orgCode = StringUtils.isEmpty(orgCode) ? "" : orgCode;
        log.info("查询服务配置入参queryServiceConfig：" + JSONUtils.toString(qo));
        //先尝试查询机构下的服务配置
        ServItemConf itemConf = servItemConfDAO.getByManageUnit(tenantId, orgCode, serviceName);
        log.info("查询服务配置出参itemConf：" + JSONUtils.toString(itemConf));

        //查不到查询租户下的服务配置
        if (Objects.isNull(itemConf)) {
            itemConf = servItemConfDAO.getByManageUnit(tenantId, "", serviceName);
        }

        //再查不到返回空
        if (Objects.isNull(itemConf)) {
            return null;
        }
        //再去获取基础配置
        ServiceConfigVO allConfig = getAllConfigByItem(itemConf);

        //查询机构的服务鉴权配置
        ServiceConfigVO.ServiceAuth serviceAuth = getOrgServiceAuth(tenantId, orgCode);
        if(Objects.nonNull(allConfig)) {
            allConfig.setServiceAuth(serviceAuth);
        }

        return allConfig;
    }

    /**
     * 查询机构的服务鉴权配置
     */
    private ServiceConfigVO.ServiceAuth getOrgServiceAuth(String tenantId, String orgCd) {
        try {
            if(StringUtils.isEmpty(orgCd)){
                orgCd = "";
            }
            ServAuthConfig query = new ServAuthConfig();
            query.setTenantId(tenantId);
            query.setOrgCd(orgCd);
            query.setFgActive(true);
            ServAuthConfig config = servAuthConfigDAO.selectOne(query);
            if (Objects.nonNull(config)) {
                ServiceConfigVO.ServiceAuth serviceAuth = new ServiceConfigVO.ServiceAuth();
                BeanUtils.copyProperties(config, serviceAuth);
                return serviceAuth;
            }
            return null;
        } catch (Exception e) {
            log.error("查询机构的服务鉴权配置失败", e);
        }
        return null;
    }

    @Override
    public ServiceConfigVO queryServiceConfigById(String id) {
        ServItemConf itemConf = servItemConfDAO.get(id);
        if (Objects.isNull(itemConf)) {
            return null;
        }
        ServiceConfigVO allConfig = getAllConfigByItem(itemConf);

        //查询机构的服务鉴权配置
        ServiceConfigVO.ServiceAuth serviceAuth = getOrgServiceAuth(itemConf.getTenantId(), itemConf.getOrgCd());
        if(Objects.nonNull(allConfig)) {
            allConfig.setServiceAuth(serviceAuth);
        }

        return allConfig;
    }

    @Override
    public List<TemplateDTO> getAllTemplateList() {
        ServItemTemplate query = new ServItemTemplate();
        query.setActive(true);
        List<ServItemTemplate> servItemTemplates = servItemTemplateDAO.selectList(query);
        if (CollectionUtils.isEmpty(servItemTemplates)) {
            return Collections.emptyList();
        }
        return servItemTemplates.stream().map(temp -> {
            TemplateDTO dto = new TemplateDTO();
            dto.setTenantId(temp.getTenantId());
            dto.setOrgCd(temp.getOrgCd());
            dto.setServiceName(temp.getServiceName());
            dto.setRequest(temp.getRequest());
            dto.setTemplate(temp.getServiceTemplate());
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public TemplateDTO getTemplate(TemplateDTO dto) {
        ServItemTemplate query = new ServItemTemplate();
        query.setActive(true);
        query.setTenantId(dto.getTenantId());
        query.setOrgCd(dto.getOrgCd());
        query.setServiceName(dto.getServiceName());
        ServItemTemplate template = servItemTemplateDAO.selectOne(query);
        if (Objects.isNull(template)) {
            return null;
        }
        TemplateDTO rtn = new TemplateDTO();
        rtn.setTenantId(template.getTenantId());
        rtn.setOrgCd(template.getOrgCd());
        rtn.setServiceName(template.getServiceName());
        rtn.setRequest(template.getRequest());
        rtn.setTemplate(template.getServiceTemplate());
        return rtn;
    }

    /**
     * 根据服务配置查询系统配置并拼装返回
     */
    private ServiceConfigVO getAllConfigByItem(ServItemConf itemConf) {
        String tenantId = itemConf.getTenantId();
        String sysType = itemConf.getSysType();
        ServBaseConf servBaseConf = servBaseConfDAO.getByManageUnit(tenantId, itemConf.getOrgCd(), sysType);
        if (Objects.isNull(servBaseConf)) {
            servBaseConf = servBaseConfDAO.getByManageUnit(tenantId, "", sysType);
        }
        if (Objects.isNull(servBaseConf)) {
            return null;
        }
        ServiceConfigVO vo = new ServiceConfigVO();
        vo.setTenantId(servBaseConf.getTenantId());
        vo.setOrgCd(servBaseConf.getOrgCd());
        vo.setSysType(servBaseConf.getSysType());
        vo.setServiceUrl(servBaseConf.getServiceUrl());
        vo.setProtocol(servBaseConf.getProtocol());
        vo.setContentTpl(servBaseConf.getContentTpl());
        vo.setContentType(servBaseConf.getContentType());
        vo.setContactUrl(servBaseConf.getContactUrl());
        vo.setUseTpl(servBaseConf.getUseTpl());

        vo.setServiceName(itemConf.getServiceName());
        vo.setServiceType(itemConf.getServiceType());
        vo.setRestfulUri(itemConf.getRestfulUri());
        vo.setWebserviceName(itemConf.getWebserviceName());
        vo.setRpcServiceId(itemConf.getRpcServiceId());
        vo.setRpcServiceMethod(itemConf.getRpcServiceMethod());
        vo.setInvokeDirection(itemConf.getInvokeDirection());
        String itemConfServiceVersion = itemConf.getServiceVersion();
        String baseConfServiceVersion = servBaseConf.getServiceVersion();

        String serviceVersion = StringUtils.isEmpty(itemConfServiceVersion) ? baseConfServiceVersion : itemConfServiceVersion;
        vo.setServiceVersion(serviceVersion);

        return vo;
    }


    @RpcService
    public void checkPwd(String md5Pwd) throws ControllerException {
        UserRoleToken current = UserRoleToken.getCurrent();
        if ((Objects.isNull(current))) {
            throw new ServiceException("未登录");
        }
        String userId = current.getUserId();
        User user = UserController.instance().get(userId);
        boolean b = user.validateMD5Password(md5Pwd);
        if (!b) {
            throw new ServiceException("密码不正确");
        }
    }

    /**
     * 查询系统配置列表 4.0.2增加字段
     */
    @RpcService
    public SimplePageInfo<SystemConfigListVO> getSysConfigList(SystemConfigListDTO dto) {
        if (StringUtils.isEmpty(dto.getTenantId())) {
            dto.setTenantId(UserRoleToken.getCurrentTenantId());
        }
        return servBaseConfDAO.getSysConfigList(dto);
    }

    /**
     * 查询当前对接系统在该机构是否存在（假如存在返回true，假如不存在去该机构对应的租户去查找，存在返回true，不存在返回false）
     */
    @RpcService
    public boolean getDockingSystem(QueryConfigListDTO dto) {
        ServBaseConf conf = getSysConfigByType(dto);
        return Objects.nonNull(conf);
    }

    /**
     * 根据系统类型查询出对应的系统配置
     */
    @RpcService
    public ServBaseConf getSysConfigByType(QueryConfigListDTO dto) {
        ServBaseConf conf = servBaseConfDAO.getByManageUnit(dto.getTenantId(), dto.getOrgCd(), dto.getSysType());
        if (Objects.isNull(conf)) {
            String orgCd = "";
            conf = servBaseConfDAO.getByManageUnit(dto.getTenantId(), orgCd, dto.getSysType());
        }
        return conf;
    }


    /**
     * 查询服务列表 4.0.2增加字段
     */
    @RpcService
    public SimplePageInfo<ServiceConfigListVO> getServiceConfigList(ServiceConfigListDTO dto) {

        if (StringUtils.isEmpty(dto.getTenantId())) {
            dto.setTenantId(UserRoleToken.getCurrentTenantId());
        }

        SimplePageInfo<ServiceConfigListVO> serviceConfigList = servItemConfDAO.getServiceConfigList(dto);
        List<ServiceConfigListVO> list = serviceConfigList.getList();
        if (CollectionUtils.isEmpty(list)) {
            return serviceConfigList;
        }
        String orgCd = dto.getOrgCd();
        String realOrgCd = StringUtils.isEmpty(orgCd) ? "" : orgCd;
        String tenantId = UserRoleToken.getCurrentTenantId();
        ArrayList<SystemTypeEnum> orgConfigEnum = getOrgConfigEnum(tenantId, realOrgCd);
        Map<String, SystemTypeEnum> map = new HashMap<>();
        if (!CollectionUtils.isEmpty(orgConfigEnum)) {
            map = orgConfigEnum.stream().collect(Collectors.toMap(SystemTypeEnum::getType, v -> v, (v1, v2) -> v1));
        }
        for (ServiceConfigListVO s : list) {
            String sysType = s.getSysType();
            boolean containsKey = map.containsKey(sysType);
            s.setValidFlag(containsKey);
        }
        return serviceConfigList;
    }


    /**
     * 保存系统配置  4.0.2增加字段
     */
    @RpcService
    public void saveSysConfig(SaveSystemConfigDTO dto) {
        if (StringUtils.isEmpty(dto.getTenantId())) {
            dto.setTenantId(UserRoleToken.getCurrentTenantId());
        }
        if (StringUtils.isEmpty(dto.getOrgCd())) {
            dto.setOrgCd("");
        }
        String configId = dto.getConfigId();
        String opName = getOpName();
        //校验系统类型是否重复
        boolean exist = verifySysConfigRepeat(dto);
        if (exist) {
            String sysType = dto.getSysType();
            try {
                Dictionary dictionary = DictionaryController.instance().get("hcn.base.dictionary.systemType");
                DictionaryItem item = dictionary.getItem(dto.getSysType());
                String text = item.getText();
                String errorMsg = "此租户/机构下已存在【{0}】系统,不可重复添加";
                String msg = MessageFormat.format(errorMsg, text);
                throw new ServiceException(msg);
            } catch (ControllerException e) {
                throw new ServiceException("此租户/机构下已存在相同系统,不可重复添加");
            }

        }


        ServBaseConf conf = new ServBaseConf();

        if (StringUtils.hasText(configId)) {
            //update
            BeanUtils.copyProperties(dto, conf);
            conf.setUpdateTime(new Date());
            conf.setOpName(opName);
            servBaseConfDAO.updateSelective(conf);
        } else {
            //insert
            BeanUtils.copyProperties(dto, conf);
            conf.setConfigId(KeyGenerator.randomGenerate());
            conf.setCreateTime(new Date());
            conf.setUpdateTime(new Date());
            conf.setOpName(opName);
            servBaseConfDAO.insertSelective(conf);
        }
    }

    private boolean verifySysConfigRepeat(SaveSystemConfigDTO dto) {
        ServBaseConf query = new ServBaseConf();
        query.setTenantId(dto.getTenantId());
        query.setOrgCd(dto.getOrgCd());
        query.setSysType(dto.getSysType());
        ServBaseConf exist = servBaseConfDAO.selectOne(query);
        return Objects.nonNull(exist) &&
                (StringUtils.isEmpty(dto.getConfigId()) || StringUtils.hasText(dto.getConfigId()) && !exist.getConfigId().equals(dto.getConfigId()));
    }

    /**
     * 查询系统配置详情 4.0.2 增加字段
     */
    @RpcService
    public SystemConfigVO getSysConfig(String id) {
        ServBaseConf servBaseConf = servBaseConfDAO.get(id);
        if (Objects.isNull(servBaseConf)) {
            return null;
        }
        SystemConfigVO vo = new SystemConfigVO();
        BeanUtils.copyProperties(servBaseConf, vo);
        return vo;
    }

    /**
     * 删除系统配置
     */
    @RpcService
    public void delSysConfig(String id) {
        servBaseConfDAO.remove(id);
    }

    /**
     * 查询服务配置详情 4.0.2 增加字段
     */
    @RpcService
    public ServiceConfigDetailVO getServiceConfig(String id) {
        ServItemConf servItemConf = servItemConfDAO.get(id);
        if (Objects.isNull(servItemConf)) {
            return null;
        }
        ServiceConfigDetailVO vo = new ServiceConfigDetailVO();
        BeanUtils.copyProperties(servItemConf, vo);
        return vo;
    }


    /**
     * 批量更新服务配置
     */
    @RpcService
    public void batchSaveServiceConfig(List<SaveServiceConfigDTO> dtoList) {
        if (CollectionUtils.isEmpty(dtoList)) {
            return;
        }
        String opName = getOpName();
        dtoList.forEach(dto -> {
            if (StringUtils.hasText(dto.getId())) {
                ServItemConf conf = new ServItemConf();
                //update
                BeanUtils.copyProperties(dto, conf);
                parseInstr(conf);
                conf.setUpdateTime(new Date());
                conf.setOpName(opName);
                servItemConfDAO.updateSelective(conf);
            }
        });
    }

    /**
     * 保存服务配置
     */
    @RpcService
    public void saveServiceConfig(SaveServiceConfigDTO dto) {
        if (StringUtils.isEmpty(dto.getTenantId())) {
            dto.setTenantId(UserRoleToken.getCurrentTenantId());
        }
        if (StringUtils.isEmpty(dto.getOrgCd())) {
            dto.setOrgCd("");
        }
        String id = dto.getId();
        String opName = getOpName();
        ServItemConf conf = new ServItemConf();
        if (StringUtils.hasText(id)) {
            //update
            BeanUtils.copyProperties(dto, conf);
            parseInstr(conf);
            conf.setUpdateTime(new Date());
            conf.setOpName(opName);
            servItemConfDAO.updateSelective(conf);
        } else {
            //insert
            BeanUtils.copyProperties(dto, conf);
            parseInstr(conf);
            conf.setId(KeyGenerator.randomGenerate());
            conf.setCreateTime(new Date());
            conf.setUpdateTime(new Date());
            conf.setOpName(opName);
            servItemConfDAO.insertSelective(conf);
        }
    }


    /**
     * 初始化服务路由配置
     */
    @Override
    @RpcService
    public void initServiceConfig(String orgCd) {
        String realOrgCd = StringUtils.isEmpty(orgCd) ? "" : orgCd;
        String tenantId = UserRoleToken.getCurrentTenantId();
        String realTenantId = StringUtils.isEmpty(tenantId) ? HcnBaseConst.TENANTID : tenantId;
        //先查询出机构配置的系统列表
        //服务配置
        PlatFormServiceEnum[] values = PlatFormServiceEnum.values();
        ArrayList<SystemTypeEnum> mergeSystem = getOrgConfigEnum(realTenantId, realOrgCd);
        if (CollectionUtils.isEmpty(mergeSystem)) {
            log.info("租户:{},机构:{}未配置任何系统,停止服务清单初始化", realTenantId, realOrgCd);
            return;
        }
        String opName = getOpName();
        Arrays.stream(values).forEach(v -> saveConfig(v, realOrgCd, realTenantId, mergeSystem, opName));

    }

    @Override
    public Map<String, Map<String, List<String>>> getDictMapping(String tenantId, String orgCd) {
        ServDictMapping query = new ServDictMapping();
        query.setTenantId(tenantId);
        query.setOrgCd(orgCd);
        List<ServDictMapping> list = servItemMappingDAO.selectList(query);

        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyMap();
        }
        Map<String, Map<String, List<String>>> dictMapping = new HashMap<>();

        list.forEach(item -> {
            String dictId = item.getDictId();
            String standardValue = item.getStandardValue();
            String mappingValue = item.getMappingValue();
            Map<String, List<String>> fieldMapping = dictMapping.get(dictId);
            if (CollectionUtils.isEmpty(fieldMapping)) {
                fieldMapping = new HashMap<>();
                dictMapping.put(dictId, fieldMapping);
            }
            List<String> values = fieldMapping.get(standardValue);
            if (CollectionUtils.isEmpty(values)) {
                values = new ArrayList<>();
                fieldMapping.put(standardValue, values);
            }
            values.add(mappingValue);
        });
        return dictMapping;
    }

    /**
     * 获取用户有效的
     */
    @SuppressWarnings("unchecked")
    private ArrayList<SystemTypeEnum> getOrgConfigEnum(String tenantId, String orgCd) {
        ServBaseConf query = new ServBaseConf();
        query.setTenantId(tenantId);
        query.setOrgCd(orgCd);
        query.setConfigType("2");
        query.setActive(true);
        List<ServBaseConf> orgConfigs = servBaseConfDAO.selectList(query);

        // 租户级别的配置
        ServBaseConf query2 = new ServBaseConf();
        query2.setTenantId(tenantId);
        query2.setOrgCd("");
        query2.setConfigType("1");
        query2.setActive(true);
        List<ServBaseConf> tenantConfigs = servBaseConfDAO.selectList(query2);

        if (CollectionUtils.isEmpty(orgConfigs) && CollectionUtils.isEmpty(tenantConfigs)) {
            return null;
        }
        List<SystemTypeEnum> orgSystems;
        if (CollectionUtils.isEmpty(orgConfigs)) {
            orgSystems = Collections.emptyList();
        } else {
            orgSystems = orgConfigs.stream()
                    .map(config -> SystemTypeEnum.getByType(config.getSysType())).filter(Objects::nonNull)
                    .collect(Collectors.toList());
        }
        List<SystemTypeEnum> tenantSystems;
        if (CollectionUtils.isEmpty(tenantConfigs)) {
            tenantSystems = Collections.emptyList();
        } else {
            tenantSystems = tenantConfigs.stream()
                    .map(config -> SystemTypeEnum.getByType(config.getSysType())).filter(Objects::nonNull)
                    .collect(Collectors.toList());
        }
        return (ArrayList<SystemTypeEnum>) org.apache.commons.collections.CollectionUtils.union(orgSystems, tenantSystems);

    }

    private void saveConfig(PlatFormServiceEnum service, String orgCd, String tenantId, List<SystemTypeEnum> orgSystems, String opName) {
        try {

            SystemTypeEnum[] systemTypes = service.getSystemType();
            //如果有医院平台,平台优先
            SystemTypeEnum finalSystem = filterSystem(systemTypes, orgSystems);
            if (Objects.isNull(finalSystem)) {
                finalSystem = SystemTypeEnum.HOSPITAL_PLATFORM;
            }

            ServItemConf query = new ServItemConf();
            query.setServiceName(service.getServiceName());
            query.setOrgCd(orgCd);
            query.setTenantId(tenantId);

            ServItemConf conf = servItemConfDAO.selectOne(query);
            if (Objects.nonNull(conf)) {
                return;
            }

            ServItemConf inst = new ServItemConf();
            inst.setId(KeyGenerator.randomGenerate());
            inst.setTenantId(tenantId);
            inst.setOrgCd(orgCd);
            inst.setServiceIntro(service.getServiceIntro());
            inst.setServiceName(service.getServiceName());
            inst.setServiceType(service.getServiceCode());
            inst.setServiceVersion("4.0");


            inst.setSysType(finalSystem.getType());
            inst.setRestfulUri(service.getRestfulUrlName());
            inst.setWebserviceName(service.getWebserviceName());
            inst.setOpName(opName);
            inst.setCreateTime(new Date());
            inst.setUpdateTime(new Date());
            parseInstr(inst);
            servItemConfDAO.save(inst);
        } catch (Exception e) {
            log.error("保存机构服务配置失败,tenantId-{}, orgCd-{},serviceName-{}", tenantId, orgCd, service.getServiceName());
            log.error("保存机构服务配置失败", e);
        }
    }

    @SuppressWarnings("unchecked")
    private SystemTypeEnum filterSystem(SystemTypeEnum[] systemTypes, List<SystemTypeEnum> orgSystems) {
        if (systemTypes.length == 0) {
            return null;
        }
        List<SystemTypeEnum> defaultSystems = Arrays.asList(systemTypes);
        ArrayList<SystemTypeEnum> intersection = (ArrayList<SystemTypeEnum>) org.apache.commons.collections.CollectionUtils.intersection(defaultSystems, orgSystems);
        if (CollectionUtils.isEmpty(intersection)) {
            return null;
        }
        if (intersection.contains(SystemTypeEnum.HOSPITAL_PLATFORM)) {
            return SystemTypeEnum.HOSPITAL_PLATFORM;
        } else {
            return intersection.get(0);
        }
    }

    /**
     * 重置服务路由配置
     */
    @RpcService
    @DAOTransaction
    public void resetServiceConfig(String orgCd) {
        String realOrgCd = StringUtils.isEmpty(orgCd) ? "" : orgCd;
        //删除当前机构的所有服务配置
        String tenantId = UserRoleToken.getCurrentTenantId();
        if (StringUtils.isEmpty(tenantId)) {
            return;
        }
        servItemConfDAO.deleteServiceConfig(tenantId, realOrgCd);
        initServiceConfig(realOrgCd);
    }


    private void parseInstr(ServItemConf conf) {
        List<String> str = new ArrayList<>();
        if (StringUtils.hasText(conf.getServiceIntro())) {
            str.add(conf.getServiceIntro());
        }
        if (StringUtils.hasText(conf.getServiceName())) {
            str.add(conf.getServiceName());
        }
        if (StringUtils.hasText(conf.getServiceType())) {
            str.add(conf.getServiceType());
        }
        if (!CollectionUtils.isEmpty(str)) {
            String instr = String.join(",", str);
            conf.setInstr(instr);
        }
    }

    private String getOpName() {
        UserRoleToken urt = UserRoleToken.getCurrent();
        if (Objects.isNull(urt)) {
            return "";
        }
        String userId = urt.getUserId();
        try {
            User user = UserController.instance().get(userId);
            return user.getName() + "(" + user.getLoginName() + ")";
        } catch (ControllerException e) {
            return "";
        }
    }
}
